#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
零度影视 
"""
import json
import random
import sys
import base64
import re
from urllib.parse import quote
from concurrent.futures import ThreadPoolExecutor
import requests   # 仅用于 302 跟随

sys.path.append('..')
from base.spider import Spider
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

# ---------- RSA 密钥 ----------
_PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoYt0BP77U+DM08BiI/QbSRIfx
ijXo85BTPqIM1Ow8BNwhLETzRIZ+dEwdWDbydG/PspgBAfRpGaYVdJYtvaC2JnoO
8+Ik6qMWojfEJxSFLa0Pb0A892tun4gsxoEMjcreZ+YGyaBxAfqX0BSMfdrOgIYa
ZQjYrw9TRLlUT31QoQIDAQAB
-----END PUBLIC KEY-----"""

_PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCquQQ5r6+yJI8C
DFkXRp8vUsdD45ov8EP12ooLs56ca2DQXaSNGS9910bAPVA9chkp0mKIvKqjAsHz
5Tl9EeNPblarGEeJUIxpxZtiSqNTpvtiD/TjhpzuHYic7RAfQ/h7p/ypE8ymU42p
YjsB5t26Mv6XgkLV+jzrSf73HlCuS0iMyLmt6zz3Mw9izM13EpB8iFLtfbbYymyc
KTx4RAmPQLwhNGex/AlUIYxXP4R2yyaa4W6mEtc6aME2QuzJFxPgP3HJ9NBx/LWV
n4skxWjZ7zg+VRQRHnjyVaSLu3Z5gN5ITWCyE32qaHJa6WBahZj5jWhRyAG1bQ+x
KJa8lBL5AgMBAAECggEAUwv9SjJ0PSwbhNuM2w23kcWquROWhYtTA91zGY4esehq
B/IFgb2mpIh8Gje5OKqwIu/8jpd4SiOlRYdUF8sD0DfUYRZGdj2AkFNX6tBz8tVf
o6wvbB6naA1lzzBij1L5JO3qsjS3cJFkb+kg2yP66AC2Z+0tpfk8eRhdtshAZwfc
d1DEGt1uAvYL1eaUK9HRvpt9lPeGcHERDl2hBd4uyaF0K1O+zF9y59nYbTySWPxR
Zq3sFEE85xRMlstD7YZi7W2gKvMFRD4/FKmrZ3m7aKJRITtyKOyyPcYmepNv3Qv7
kk59Pg38n2WWQ0Ra/bCH3E48YNCnQvZMpitkTfJhoQKBgQDbnROOYTP8OTJ6f/qh
oGjxeO3x1VOaOp8l0x7b0SCfoqNGS0Cyiqj72BmJtPMPqSTjn6MmNzqbg1KOdhXy
zNozs+i5ccW1M56j96mr5I/Z0FpE3oyIHNfDDBlf9M8YQqEF9oYxniYYft9oapO7
cRQkHER6qpvnHTavwlv4m78CXwKBgQDHAjs2YlpKDdI1lcbZJCc7TwtH+Pd2bUki
8YXafWNcPhITQHbOZjr310eK1QJC6GJncjkOqbX7yv3ivvTO35FZTQhuA1xEG1P0
0FG8bE0tHYPIwQHi9y0eA5cieMdo8E6XYria1mw/3fqSQEsfZyJlR32JQIoGAipM
8iO1X2nZpwKBgDkMFIhnt5lNQk+P7wsNIDWZtDWdtJnboHuy29E+Abt2A/O+mI/I
dRz2hau/1WO8DFkUnszOi+rZshhPlGP90rCbi1igtTrcrdjp/KkqNjPea5R4Owkg
dOu1uOG0NheXNzzVTQaWjk7Opjn5dWa7eP/oV+GFb/oZHJuLYVizHGsBAoGADA7r
jZEKDYCm4w5PPSr+oY5ZjaPdQrS+gLqHtMRyN82fBMGcMUdqfUfzEstzVqCEDeaS
5HuOBlK3bXzKkppjUTjksN3NQmcxgBz7RuJ9DqXCLXDcb2cwuafYCYOt+YLOEEgw
DVm+t2P44dG5e46hO+fICH/7nP+WlpD5buz4GfMCgYB57r3g/6hi9WUDnft7ZAzW
MqR0EhJVYKYy+KFEtdIPzhkkIHq5RASe88E9kzoGoZFdb3tIjvGZWcHerirrqWkM
suQtP/Qi0zjieid5tAPj+r4kbiCVTw0E0jnmPBzGInQi7lpeTTKnG1fbyS5lBS+W
mHfIuzpECgCkxhaT+LJJkg==
-----END RSA PRIVATE KEY-----"""

# ---------- RSA 工具 ----------
def _rsa_encrypt(data: str) -> str:
    key = RSA.import_key(_PUBLIC_KEY)
    cipher = PKCS1_v1_5.new(key)
    return base64.b64encode(cipher.encrypt(data.encode("utf-8"))).decode("utf-8")

def _rsa_decrypt(b64_str: str) -> str:
    key = RSA.import_key(_PRIVATE_KEY)
    cipher = PKCS1_v1_5.new(key)
    return cipher.decrypt(base64.b64decode(b64_str), None).decode("utf-8")

def _encrypt_payload(payload: dict) -> str:
    return _rsa_encrypt(json.dumps(payload, separators=(",", ":"), ensure_ascii=False))

def _decrypt_resp(b64_data: str) -> dict:
    return json.loads(_rsa_decrypt(b64_data))

# ---------- Spider ----------
class Spider(Spider):
    def init(self, extend=""):
        self.host = self.get_host()
        print(f"当前使用域名: {self.host}")
        did = self.getdid()
        self.headers.update({"deviceId": did})
        token = self.gettk()
        self.headers.update({"token": token})

    # ---------- 域名 ----------
    def get_host(self):
        cached = self.getCache("ldys_host")
        if cached:
            return cached
        try:
            r = self.fetch("http://ldyszydizhi.oss-rg-china-mainland.aliyuncs.com/domainPath(1).json", timeout=10)
            if r.status_code == 200:
                host = r.json().get("domain", "http://ldys.sq1005.top")
                self.setCache("ldys_host", host, 3600)
                return host
        except Exception as e:
            print(f"域名获取失败: {e}")
        return "http://ldys.sq1005.top"

    # ---------- token & did ----------
    def gettk(self):
        return self.fetch(f"{self.host}/api/v1/app/user/visitorInfo", headers=self.headers).json()["data"]["token"]

    def getdid(self):
        did = self.getCache("ldid")
        if not did:
            did = "".join(random.choice("0123456789abcdef") for _ in range(16))
            self.setCache("ldid", did)
        return did

    # ---------- 详情（RSA+并发） ----------
    def detailContent(self, ids):
        ids = ids[0].split("@@")
        jdata = {"id": int(ids[0]), "typeId": ids[-1]}
        v = self.post(f"{self.host}/api/v1/app/play/movieDesc", headers=self.headers, json=jdata).json()["data"]
        vod = {
            "type_name": v.get("classify"),
            "vod_year": v.get("year"),
            "vod_area": v.get("area"),
            "vod_actor": v.get("star"),
            "vod_director": v.get("director"),
            "vod_content": v.get("introduce"),
            "vod_play_from": "",
            "vod_play_url": "",
        }

        key_body = {"key": _encrypt_payload({"id": int(ids[0]), "source": 0, "typeId": ids[-1]})}
        c = self.post(f"{self.host}/api/v1/app/play/movieDetails", headers=self.headers, json=key_body).json()
        decrypted = _decrypt_resp(c["data"])
        l = decrypted["moviePlayerList"]
        n = {str(i["id"]): i["moviePlayerName"] for i in l}

        def fetch_one(player):
            b = {"key": _encrypt_payload({"id": int(ids[0]), "source": 0, "typeId": ids[-1], "playerId": player["id"]})}
            r = self.post(f"{self.host}/api/v1/app/play/movieDetails", headers=self.headers, json=b).json()
            eps = _decrypt_resp(r["data"])["episodeList"]
            return player["id"], eps

        pd = {}
        with ThreadPoolExecutor(max_workers=8) as exc:
            for pid, eps in exc.map(fetch_one, l):
                pd[str(pid)] = "#".join([f'{ep["episode"]}${self.e64(json.dumps({"id": int(ids[0]), "typeId": ids[-1], "playerId": pid, "episodeId": ep["id"]))}' for ep in eps])

        w, e = [], []
        for i, x in pd.items():
            if x:
                w.append(n[i])
                e.append(x)
        vod["vod_play_from"] = "$$$".join(w)
        vod["vod_play_url"] = "$$$".join(e)
        return {"list": [vod]}

    # ---------- 播放（RSA+302+直链校验） ----------
    def playerContent(self, flag, id, vipFlags):
        jdata = json.loads(self.d64(id))
        key_body = {"key": _encrypt_payload(jdata)}
        data = self.post(f"{self.host}/api/v1/app/play/movieDetails", headers=self.headers, json=key_body).json()
        play_url = _decrypt_resp(data["data"])["url"]

        # 再请求解析接口
        analysis_url = f"{self.host}/api/v1/app/play/analysisMovieUrl?" \
                       f"playerUrl={quote(play_url)}&playerId={jdata['playerId']}"
        h = {"User-Agent": "okhttp/4.12.0", "Referer": self.host}
        rsp = requests.get(analysis_url, headers=h, allow_redirects=False)
        if 300 <= rsp.status_code < 400:                       # 302 跳转
            video = rsp.headers["Location"]
        else:                                                  # 200
            video = rsp.json().get("data") or rsp.text

        # 直链校验
        if not re.search(r'\.(m3u8|mp4|flv|mp3)$', video, re.I):
            return {"parse": 1, "url": play_url}               # 扔回框架二次解析
        return {"parse": 0, "url": video + "#isVideo=true#", "header": {"User-Agent": "okhttp/4.12.0"}}

    # ---------- 其余原函数 ----------
    def isVideoFormat(self, url):
        pass

    def manualVideoCheck(self):
        pass

    def getName(self):
        pass

    def destroy(self):
        pass

    def homeContent(self, filter):
        data = self.post(f"{self.host}/api/v1/app/screen/screenType", headers=self.headers).json()
        result = {}
        cate = {"类型": "classify", "地区": "region", "年份": "year"}
        sort = {"key": "sreecnTypeEnum", "name": "排序", "value": [{"n": "人气", "v": "POPULARITY"}, {"n": "评分", "v": "COLLECT"}, {"n": "热搜", "v": "HOT"}]}
        classes, filters = [], {}
        for k in data["data"]:
            classes.append({"type_name": k["name"], "type_id": k["id"]})
            filters[k["id"]] = [{"name": v["name"], "key": cate[v["name"]], "value": [{"n": i["name"], "v": i["name"]} for i in v["children"]]} for v in k["children"]]
            filters[k["id"]].append(sort)
        result["class"] = classes
        result["filters"] = filters
        return result

    def homeVideoContent(self):
        data = self.post(f"{self.host}/api/v1/app/recommend/recommendSubList", headers=self.headers, json={"condition": 64, "pageNum": 1, "pageSize": 40}).json()
        return {"list": self.getlist(data["data"]["records"])}

    def categoryContent(self, tid, pg, filter, extend):
        jdata = {"condition": {"sreecnTypeEnum": "NEWEST", "typeId": tid}, "pageNum": int(pg), "pageSize": 40}
        jdata["condition"].update(extend)
        data = self.post(f"{self.host}/api/v1/app/screen/screenMovie", headers=self.headers, json=jdata).json()
        return {"list": self.getlist(data["data"]["records"]), "page": pg, "pagecount": 9999, "limit": 90, "total": 999999}

    def searchContent(self, key, quick, pg="1"):
        data = self.post(f"{self.host}/api/v1/app/search/searchMovie", headers=self.headers, json={"condition": {"value": key}, "pageNum": int(pg), "pageSize": 40}).json()
        return {"list": self.getlist(data["data"]["records"]), "page": pg}

    def localProxy(self, param):
        pass

    def liveContent(self, url):
        pass

    # ---------- 工具 ----------
    def getlist(self, data):
        return [{"vod_id": f'{i["id"]}@@{i["typeId"]}', "vod_name": i.get("name"), "vod_pic": i.get("cover"), "vod_year": i.get("year"), "vod_remarks": i.get("totalEpisode")} for i in data]

    def e64(self, text):
        return base64.b64encode(text.encode("utf-8")).decode("utf-8")

    def d64(self, encoded_text):
        return base64.b64decode(encoded_text.encode("utf-8")).decode("utf-8")

    headers = {
        "User-Agent": "okhttp/4.12.0",
        "client": "app",
        "deviceType": "Android"
    }


# ====================== 调试入口 ======================
if __name__ == "__main__":
    s = Spider()
    s.init()
    # 测试播放
    test_id = s.e64(json.dumps({"id": 12345, "typeId": "M15", "playerId": 7, "episodeId": 9}))
    print("最终直链：", s.playerContent("", test_id, [])["url"])
